package com.yeyks.commonReference.service.activity.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.yeyks.activity.dal.domain.*;
import com.yeyks.activity.service.*;
import com.yeyks.common.constants.MessageTemplate;
import com.yeyks.common.constants.activity.ActivityPrizeInfoTypeConstant;
import com.yeyks.common.constants.activity.RedisKeyPreConstant;
import com.yeyks.common.constants.consumer.UserInviteRelationTypeConstant;
import com.yeyks.common.em.UserBillType;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.param.PageParam;
import com.yeyks.common.utils.FormatUtils;
import com.yeyks.common.utils.RedisUtil;
import com.yeyks.common.utils.SystemStrackUtil;
import com.yeyks.common.utils.base.PhoneUtil;
import com.yeyks.commonReference.pojo.vo.activity.DoubleDan.ActivityDoubleDanGetCarouselVo;
import com.yeyks.commonReference.service.activity.ActivityBaseService;
import com.yeyks.commonReference.service.consumer.UserCouponInfoService;
import com.yeyks.commonReference.service.other.CouponInfoService;
import com.yeyks.consumer.dal.domain.MessageNotice;
import com.yeyks.consumer.dal.domain.UserCouponInfo;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.consumer.service.MessageNoticeService;
import com.yeyks.consumer.service.UserAccountOverviewService;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.other.dal.domain.CouponInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class ActivityBaseServiceImpl implements ActivityBaseService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ActivityUserJoinRecordService activityUserJoinRecordService;
    @Autowired
    private ActivityDrawRecordNewService activityDrawRecordNewService;
    @Autowired
    private ActivityListService activityListService;
    @Autowired
    private ActivityPrizeInfoService activityPrizeInfoService;
    @Autowired
    private ActivityPrizeListService activityPrizeListService;
    @Autowired
    private ActivityNodeUserRecordService activityNodeUserRecordService;

    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private CouponInfoService couponInfoService;
    @Autowired
    private UserCouponInfoService userCouponInfoService;
    @Autowired
    private UserAccountOverviewService userAccountOverviewService;
    @Autowired
    private MessageNoticeService messageNoticeService;

    //获取活动信息
    @Override
    public ActivityList getActivityDetail(String activityCode) {
        ActivityList activityList = activityListService.getActivityListByActivityCode(activityCode);
        return activityList;
    }

    //轮播
    @Override
    public List<ActivityDoubleDanGetCarouselVo> getCarousel(String activityCode, PageParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        //获取奖品列表
        List<ActivityDrawRecordNew> activityDrawRecordNewList = activityDrawRecordNewService.list(
                new QueryWrapper<ActivityDrawRecordNew>()
                        .eq(ActivityDrawRecordNew.ACTIVITY_CODE, activityCode)
                        .orderByDesc(ActivityDrawRecordNew.CREATE_TIME)
        );
        //封装返回值
        List<ActivityDoubleDanGetCarouselVo> list = new ArrayList<>();
        for (ActivityDrawRecordNew activityDrawRecordNew : activityDrawRecordNewList) {
            ActivityDoubleDanGetCarouselVo activityDoubleDanGetCarouselVo = BeanUtil.toBean(activityDrawRecordNew, ActivityDoubleDanGetCarouselVo.class);
            activityDoubleDanGetCarouselVo.setPhone(PhoneUtil.replace(activityDoubleDanGetCarouselVo.getPhone()));
            list.add(activityDoubleDanGetCarouselVo);
        }
        return list;
    }

    //记录参与的用户
    @Override
    public boolean recordParticipation(String activityCode, Integer userId) {
        if (StrUtil.isNotBlank(activityCode) && Objects.nonNull(userId)) {
            return redisUtil.runWithLock(RedisKeyPreConstant.LOCK_ACTIVITY_USER_PARTICIPATE_PRE + activityCode, () -> {
                try {
                    //查询
                    ActivityUserJoinRecord activityUserJoinRecord = activityUserJoinRecordService.getOne(
                            new QueryWrapper<ActivityUserJoinRecord>()
                                    .eq(ActivityUserJoinRecord.ACTIVITY_CODE, activityCode)
                                    .eq(ActivityUserJoinRecord.USER_ID, userId)
                                    .last("limit 1")
                    );
                    //如果第一次抽奖就存储记录
                    if (Objects.isNull(activityUserJoinRecord)) {
                        activityUserJoinRecord = new ActivityUserJoinRecord();
                        activityUserJoinRecord.setActivityCode(activityCode).setUserId(userId);
                        activityUserJoinRecordService.save(activityUserJoinRecord);
                        return true;
                    }
                } catch (Throwable e) {
                }
                return false;
            });
        }
        return false;
    }

    //获取参与的用户的数量
    @Override
    public int getParticipationCount(String activityCode) {
        int count = activityUserJoinRecordService.count(
                new QueryWrapper<ActivityUserJoinRecord>()
                        .eq(ActivityUserJoinRecord.ACTIVITY_CODE, activityCode)
        );
        return count;
    }

    //获取参与的活动节点记录
    @Override
    public List<ActivityNodeUserRecord> getActivityNodeJoinList(String activityCode, Integer userId) {
        List<ActivityNodeUserRecord> list = activityNodeUserRecordService.list(
                new QueryWrapper<ActivityNodeUserRecord>()
                        .eq(ActivityNodeUserRecord.USER_ID, userId)
                        .eq(ActivityNodeUserRecord.ACTIVITY_CODE, activityCode)
        );
        return list;
    }

    //获取基础抽奖列表
    @Override
    public List<ActivityPrizeInfo> getActivityPrizeInfoList(String activityCode) {
        return getActivityPrizeInfoList(activityCode, 1, null);
    }

    //获取基础抽奖列表
    @Override
    public List<ActivityPrizeInfo> getActivityPrizeInfoList(String activityCode, Integer level) {
        return getActivityPrizeInfoList(activityCode, level, null);
    }

    //获取基础抽奖列表
    @Override
    public List<ActivityPrizeInfo> getActivityPrizeInfoList(String activityCode, Integer level, Integer parentId) {
        return activityPrizeInfoService.list(
                new QueryWrapper<ActivityPrizeInfo>()
                        .eq(ActivityPrizeInfo.ACTIVITY_CODE, activityCode)
                        .eq(Objects.nonNull(level), ActivityPrizeInfo.LEVEL, level)
                        .eq(Objects.nonNull(parentId), ActivityPrizeInfo.PARENT_ID, parentId)
                        .eq(ActivityPrizeInfo.STATUS, 1)
        );
    }

    //生成抽奖对象
    @Override
    public WeightRandom<ActivityPrizeInfo> getWeightRandom(String activityCode, Integer level) {
        return getWeightRandom(activityCode, level, null);
    }

    //生成抽奖对象
    @Override
    public WeightRandom<ActivityPrizeInfo> getWeightRandom(String activityCode, Integer level, Integer parentId) {
        //查询生成抽奖权重
        List<ActivityPrizeInfo> list = getActivityPrizeInfoList(activityCode, level, parentId);
        WeightRandom<ActivityPrizeInfo> integerWeightRandom = getWeightRandom(list);
        return integerWeightRandom;
    }

    //生成抽奖对象
    @Override
    public WeightRandom<ActivityPrizeInfo> getWeightRandom(List<ActivityPrizeInfo> list) {
        ArrayList<WeightRandom.WeightObj<ActivityPrizeInfo>> integerWeightObjList = new ArrayList<>();
        for (ActivityPrizeInfo activityPrizeInfo : list) {
            integerWeightObjList.add(new WeightRandom.WeightObj<>(activityPrizeInfo, activityPrizeInfo.getChancePercent()));
        }
        WeightRandom<ActivityPrizeInfo> integerWeightRandom = new WeightRandom<>(integerWeightObjList);
        return integerWeightRandom;
    }

    //判断活动是否开始和结束
    @Override
    public void checkActivityEndDate(String activityCode) {
        //判断是否超时
        ActivityList activityList = activityListService.getActivityListByActivityCode(activityCode);
        if (Objects.nonNull(activityList)) {
            if (new Date().before(activityList.getEndTime())) {
                return;
            }
        }
        throw new ServiceException("活动已结束");
    }

    //兑换券奖品的锁
    public static final String REDEMPTION_CODE_TYPE_Lock = RedisKeyPreConstant.LOCK_ACTIVITY_DO_PRE + "lock:activity:do:giveAwayPrizes:";

    //发放奖品
    @Override
    public boolean giveAwayPrizes(String activityCode, Integer prizeId, Integer userId) {
        //查询奖品信息
        ActivityPrizeInfo activityPrizeInfo = activityPrizeInfoService.getById(prizeId);
        if (Objects.isNull(activityPrizeInfo)) {
            return false;
        }
        UserInfo userInfo = userInfoService.getById(userId);
        if (Objects.isNull(userInfo)) {
            return false;
        }
        //
        boolean flag = false;
        //生成奖品记录
        ActivityDrawRecordNew activityDrawRecordNew = new ActivityDrawRecordNew();
        activityDrawRecordNew.setUserId(userId);
        activityDrawRecordNew.setPhone(userInfo.getPhone());
        activityDrawRecordNew.setActivityCode(activityCode);
        activityDrawRecordNew.setPrizeId(prizeId);
        activityDrawRecordNew.setPrizeName(activityPrizeInfo.getPrizeName());
        activityDrawRecordNew.setEndTime(activityPrizeInfo.getEndTime());
//        activityDrawRecordNew.setResultContent();
//        activityDrawRecordNew.setPrizeListId();
//        activityDrawRecordNew.setPrizePrice();
//        activityDrawRecordNew.setStatus();
        /**
         {@link ActivityPrizeInfoTypeConstant}
         */
        try {
            switch (activityPrizeInfo.getPrizeType()) {
                case 1:
                    flag = sendGoods(activityDrawRecordNew, activityPrizeInfo, prizeId);
                    break;
                case 2:
                    flag = sendCard(activityDrawRecordNew, activityPrizeInfo, activityCode, prizeId);
                    break;
                case 3:
                    flag = sendCoupons(activityDrawRecordNew, activityPrizeInfo, prizeId, userId);
                    break;
                case 4:
                    flag = sendRedEnvelope(activityPrizeInfo.getPrizePrice(), activityCode, userId, prizeId);
                    break;
                case 99:
                    break;
                default:
                    throw new ServiceException("奖品类型有误");
            }
        } catch (Exception e) {
            if (e instanceof ServiceException) {
                throw e;
            } else {
                SystemStrackUtil.logYyksExceptionStack(e);
            }
        }
        //存储奖品记录
        return flag;
    }

    //发实物
    private boolean sendGoods(ActivityDrawRecordNew activityDrawRecordNew, ActivityPrizeInfo activityPrizeInfo, Integer prizeId) {
        return redisUtil.runWithLock(REDEMPTION_CODE_TYPE_Lock + prizeId, () -> {
            //修改奖品数量
            if (!reduceTheNumberOfPrizes(prizeId)) {
                return false;
            }
            //存储奖品
            activityDrawRecordNew.setStatus(0);
            activityDrawRecordNew.setPrizeType(activityPrizeInfo.getPrizeType());
            activityDrawRecordNew.setResultContent(String.format("恭喜获得%s!", activityPrizeInfo.getPrizeName()));
            activityDrawRecordNewService.save(activityDrawRecordNew);
            return true;
        });
    }

    //发卡
    private boolean sendCard(ActivityDrawRecordNew activityDrawRecordNew, ActivityPrizeInfo activityPrizeInfo, String activityCode, Integer prizeId) {
        return redisUtil.runWithLock(REDEMPTION_CODE_TYPE_Lock + prizeId, () -> {
            //查询兑换码
            ActivityPrizeList activityPrizeList = activityPrizeListService.getOne(
                    new QueryWrapper<ActivityPrizeList>()
                            .eq(ActivityPrizeList.ACTIVITY_CODE, activityCode)
                            .eq(ActivityPrizeList.PRIZE_ID, prizeId)
                            .eq(ActivityPrizeList.STATUS, 0)
                            .last("limit 1")
            );
            if (Objects.isNull(activityPrizeList)) {
                return false;
            }
            //修改记录
            //修改奖品数量
            if (!reduceTheNumberOfPrizes(prizeId)) {
                return false;
            }
            //修改邀请码
            boolean update = activityPrizeListService.update(
                    new UpdateWrapper<ActivityPrizeList>()
                            .set(ActivityPrizeList.STATUS, 1)
                            .eq(ActivityPrizeList.ID, activityPrizeList.getId())
            );
            //存储奖品
            activityDrawRecordNew.setPrizeType(activityPrizeInfo.getPrizeType());
            activityDrawRecordNew.setRedeemCode(activityPrizeList.getRedeemCode());
            activityDrawRecordNew.setPrizeListId(activityPrizeList.getId());
            activityDrawRecordNew.setPrizePrice(String.valueOf(activityPrizeInfo.getPrizePrice()));
            activityDrawRecordNew.setStatus(1);
            activityDrawRecordNew.setResultContent(String.format("兑换码:%s", activityPrizeList.getRedeemCode()));
            activityDrawRecordNewService.save(activityDrawRecordNew);
            return true;
        });
    }

    //发券
    private boolean sendCoupons(ActivityDrawRecordNew activityDrawRecordNew, ActivityPrizeInfo activityPrizeInfo, Integer prizeId, Integer userId) {
        return redisUtil.runWithLock(REDEMPTION_CODE_TYPE_Lock + prizeId, () -> {
            //获取可发的券
            CouponInfo couponInfo = couponInfoService.getOne(
                    new QueryWrapper<CouponInfo>()
                            .eq(CouponInfo.ID, activityPrizeInfo.getCouponId())
                            .last("limit 1")
            );
            //判断是否有券
            if (Objects.isNull(couponInfo) || CompareUtil.compare(couponInfo.getRemainCount(), 0) <= 0) {
                return false;
            }
            //修改奖品数量
//            ActivityPrizeInfo activityPrizeInfo_n = activityPrizeInfoService.getById(prizeId);
//            activityPrizeInfoService.update(
//                    new UpdateWrapper<ActivityPrizeInfo>()
//                            .set(ActivityPrizeInfo.REMAIN_COUNT, activityPrizeInfo_n.getRemainCount() - 1)
//                            .set(ActivityPrizeInfo.TAKE_COUNT, activityPrizeInfo_n.getTakeCount() + 1)
//                            .eq(ActivityPrizeInfo.ID, activityPrizeInfo_n.getId())
//            );
            //减少券的余量
            couponInfoService.update(
                    new UpdateWrapper<CouponInfo>()
                            .set(CouponInfo.GET_COUNT, couponInfo.getGetCount() + 1)
                            .set(CouponInfo.REMAIN_COUNT, couponInfo.getRemainCount() - 1)
                            .eq(CouponInfo.ID, couponInfo.getId())
            );
            //添加券
            UserCouponInfo userCouponInfo = new UserCouponInfo();
            Date date = new Date();
            userCouponInfo.setGmtCreate(date);
            userCouponInfo.setGmtModified(date);
            userCouponInfo.setOverTime(DateUtil.offsetDay(date, couponInfo.getDuration()));
            userCouponInfo.setUserId(userId);
            userCouponInfo.setCouponId(couponInfo.getId());
            userCouponInfo.setCouponValue(couponInfo.getPrice());
            userCouponInfo.setSource(3);
            userCouponInfo.setUsed(0);
            userCouponInfoService.save(userCouponInfo);
            //记录
            activityDrawRecordNew.setPrizeType(activityPrizeInfo.getPrizeType());
            activityDrawRecordNew.setPrizePrice(String.valueOf(activityPrizeInfo.getPrizePrice()));
            activityDrawRecordNew.setStatus(1);
            activityDrawRecordNew.setResultContent(String.format("恭喜获得%s!", couponInfo.getTitle()));
            activityDrawRecordNew.setEndTime(userCouponInfo.getOverTime());
            activityDrawRecordNewService.save(activityDrawRecordNew);
            return true;
        });
    }

    //发计数奖品红包
    private boolean sendRedEnvelope(Integer amount, String activityCode, Integer userId, Integer prizeId) {
        //修改记录
        //修改奖品数量
        if (!reduceTheNumberOfPrizes(prizeId)) {
            return false;
        }
        return sendRedEnvelope(amount, activityCode, userId);
    }

    //修改奖品数量,-1
    private boolean reduceTheNumberOfPrizes(Integer prizeId) {
        //修改奖品数量
        ActivityPrizeInfo activityPrizeInfo_n = activityPrizeInfoService.getById(prizeId);
        if (activityPrizeInfo_n.getRemainCount() < 1) {
            return false;
        }
        activityPrizeInfoService.update(
                new UpdateWrapper<ActivityPrizeInfo>()
                        .set(ActivityPrizeInfo.REMAIN_COUNT, activityPrizeInfo_n.getRemainCount() - 1)
                        .set(ActivityPrizeInfo.TAKE_COUNT, activityPrizeInfo_n.getTakeCount() + 1)
                        .eq(ActivityPrizeInfo.ID, activityPrizeInfo_n.getId())
        );
        return true;
    }

    //发红包
    @Override
    public boolean sendRedEnvelope(Integer amount, String activityCode, Integer userId) {
        switch (activityCode) {
            case "DoubleDan":
                //发红包
                userAccountOverviewService.addAmount(amount, userId, UserBillType.DOUBLE_DAN.value(), UserBillType.DOUBLE_DAN.desc(), UserInviteRelationTypeConstant.INVITE_ACTIVITY_DOUBLE_DAN);
                //存红包记录
                Map<String, Object> map = new HashMap<>();
                map.put("amount", FormatUtils.fenToYuan(amount));
                messageNoticeService.saveMessageNoticeSimple(MessageTemplate.ACTIVITY_DOUBLE_DAN, map, userId, MessageNotice.Type.ACTIVITY_DOUBLE_DAN.value());
                break;
            default:
                break;
        }
        return true;
    }

    //获取奖品明细
    @Override
    public List<ActivityDrawRecordNew> getAwardDetails(String activityCode, Integer userId) {
        List<ActivityDrawRecordNew> activityDrawRecordNewList = activityDrawRecordNewService.list(
                new QueryWrapper<ActivityDrawRecordNew>()
                        .eq(ActivityDrawRecordNew.ACTIVITY_CODE, activityCode)
                        .eq(ActivityDrawRecordNew.USER_ID, userId)
                        .orderByDesc(ActivityDrawRecordNew.CREATE_TIME)
        );
        return activityDrawRecordNewList;
    }

}
